
--[[
	*******************
	* MCServer Plugin *
	*******************
	Author: thomasfn
	Name: admin
	Description: Provides basic admin chat commands
--]]

local plugin = {}

FLAG_ALL = 0
FLAG_KICK = 1
FLAG_BAN = 2
FLAG_CHANGERANK = 3
FLAG_BROADCAST = 4
FLAG_TELEPORT = 5
FLAG_SETTIME = 6
FLAG_CHANGEHEALTH = 7
FLAG_CHANGEPVP = 8

local Ranks = {
	[0] = { "Guest", COL_GRAY, {} },
	[1] = { "Respected", COL_TEAL, {} },
	[2] = { "Moderator", COL_DARKRED, { FLAG_KICK, FLAG_BROADCAST, FLAG_CHANGEHEALTH } },
	[3] = { "Administrator", COL_BLUE, { FLAG_KICK, FLAG_BAN, FLAG_BROADCAST, FLAG_TELEPORT, FLAG_SETTIME, FLAG_CHANGEHEALTH, FLAG_CHANGEPVP } },
	[4] = { "Owner", COL_GOLD, { FLAG_ALL } },
}

local Aliases = {
	guest = 0,
	respected = 1,
	mod = 2,
	moderator = 2,
	admin = 3,
	administrator = 3,
	owner = 4
}

local function GetRank( ply )
	local id = ply:Rank()
	return Ranks[ id ] or Ranks[ 0 ]
end

local function RankHasFlag( rank, flag )
	local lst = rank[3]
	for i=1, #lst do
		local id = lst[i]
		if ((id == flag) or (id == FLAG_ALL)) then return true end
	end
	return false
end

local function ValidateFlags( ply, ... )
	local flags = { ... }
	local rank = GetRank( ply )
	for i=1, #flags do
		if (not RankHasFlag( rank, flags[i] )) then
			ply:SendChat( COL_DARKRED .. "You do not have a high enough rank to do this!" )
			return false
		end
	end
	return true
end

function plugin.PlayerColour( ply, rank )
	return Ranks[ rank ][2]
end

function plugin.PlayerBanEnded( ply )
	ply:SendChat( COL_DARKRED .. "Your ban has ended. Reoffending may result in a larger ban." )
	ply:SendChat( COL_DARKRED .. "You have been warned." )
end

function plugin.PlayerChatCommand( ply, cmd, args )
	if (cmd == "kick") then
		if (not ValidateFlags( ply, FLAG_KICK )) then return true end
		if (not args[1]) then
			ply:SendChat( "Syntax: /kick <name> [reason]" )
			return true
		end
		local plist = util.FindPlayers( args[1] )
		if (#plist == 0) then
			ply:SendChat( COL_DARKRED .. "No players found by this name!" )
			return true
		end
		if (#plist > 1) then
			ply:SendChat( COL_DARKRED .. "Multiple players found by this name!" )
			return true
		end
		local pl = plist[1]
		if ((pl:Rank() >= ply:Rank()) and (not (pl == ply))) then
			ply:SendChat( COL_DARKRED .. "That player is of equal or higher rank to you!" )
			return true
		end
		local reason = ""
		local tmp = {}
		for i=2, #args do
			table.insert( tmp, args[i] )
		end
		reason = table.concat( tmp, " " )
		if (reason == "") then reason = "Kicked" end
		pl:Kick( reason )
		return true
	end
	if (cmd == "ban") then
		if (not ValidateFlags( ply, FLAG_BAN )) then return true end
		if (not args[1]) then
			ply:SendChat( "Syntax: /ban <name> <duration(hours)>" )
			return true
		end
		local plist = util.FindPlayers( args[1] )
		if (#plist == 0) then
			ply:SendChat( COL_DARKRED .. "No players found by this name!" )
			return true
		end
		if (#plist > 1) then
			ply:SendChat( COL_DARKRED .. "Multiple players found by this name!" )
			return true
		end
		local pl = plist[1]
		if ((pl:Rank() >= ply:Rank()) and (not (pl == ply))) then
			ply:SendChat( COL_DARKRED .. "That player is of equal or higher rank to you!" )
			return true
		end
		local hrs = tonumber( args[2] )
		if (not hrs) then
			ply:SendChat( "Syntax: /ban <name> <duration(hours)>" )
			return true
		end
		pl:Ban( hrs )
		pl:Kick( "Banned for " .. tostring( hrs ) .. " hours." )
		return true
	end
	if (cmd == "setrank") then
		if (not ValidateFlags( ply, FLAG_CHANGERANK )) then return true end
		if (not args[1]) then
			ply:SendChat( "Syntax: /setrank <name> <rank>" )
			return true
		end
		local plist = util.FindPlayers( args[1] )
		if (#plist == 0) then
			ply:SendChat( COL_DARKRED .. "No players found by this name!" )
			return true
		end
		if (#plist > 1) then
			ply:SendChat( COL_DARKRED .. "Multiple players found by this name!" )
			return true
		end
		local pl = plist[1]
		if ((pl:Rank() >= ply:Rank()) and (not (pl == ply))) then
			ply:SendChat( COL_DARKRED .. "That player is of equal or higher rank to you!" )
			return true
		end
		local strrank = args[2]
		local rank = tonumber( strrank ) or 0
		if (Aliases[ strrank ]) then rank = Aliases[ strrank ] end
		if (rank == pl:Rank()) then
			ply:SendChat( COL_DARKRED .. "That player is already that rank!" )
			return true
		end
		if (rank > ply:Rank()) then
			ply:SendChat( COL_DARKRED .. "You can't set rank to higher than your own!" )
			return true
		end
		if (not Ranks[ rank ]) then
			ply:SendChat( COL_DARKRED .. "Invalid rank!" )
			return true
		end
		pl:SetRank( rank )
		util.BroadcastChat( pl:CNick() .. " now has the rank " .. Ranks[rank][1] .. "." )
		return true
	end
	if (cmd == "broadcast") or (cmd == "bc") then
		if (not ValidateFlags( ply, FLAG_BROADCAST )) then return true end
		local msg = ""
		local tmp = {}
		for i=1, #args do
			table.insert( tmp, args[i] )
		end
		msg = table.concat( tmp, " " )
		if (msg == "") then
			ply:SendChat( "Syntax: /bc <msg>" )
			return true
		end
		util.BroadcastChat( COL_DARKGREEN .. "[Notice] " .. COL_GRAY .. msg )
		return true
	end
	if (cmd == "settime") then
		if (not ValidateFlags( ply, FLAG_SETTIME )) then return true end
		local tm = tonumber( args[1] )
		if (not tm) then
			ply:SendChat( "Syntax: /settime <value>" )
			return true
		end
		core.EntityManager:SetTime( tm )
		util.BroadcastChat( ply:CNick() .. " has changed the time!" )
		return true
	end
	if (cmd == "slap") then
		if (not args[1]) then
			ply:SendChat( "Syntax: /slap <name>" )
			return true
		end
		local plist = util.FindPlayers( args[1] )
		if (#plist == 0) then
			ply:SendChat( COL_DARKRED .. "No players found by this name!" )
			return true
		end
		if (#plist > 1) then
			ply:SendChat( COL_DARKRED .. "Multiple players found by this name!" )
			return true
		end
		local pl = plist[1]
		if ((pl:Rank() >= ply:Rank()) and (not (pl == ply))) then
			ply:SendChat( COL_DARKRED .. "That player is of equal or higher rank to you!" )
			return true
		end
		util.BroadcastChat( ply:CNick() .. " slapped " .. pl:CNick() .. "!" )
		pl:TakeDamage( 8 )
		return true
	end
	if (cmd == "heal") then
		if (not args[1]) then
			ply:SendChat( "Syntax: /heal <name>" )
			return true
		end
		local plist = util.FindPlayers( args[1] )
		if (#plist == 0) then
			ply:SendChat( COL_DARKRED .. "No players found by this name!" )
			return true
		end
		if (#plist > 1) then
			ply:SendChat( COL_DARKRED .. "Multiple players found by this name!" )
			return true
		end
		local pl = plist[1]
		if ((pl:Rank() >= ply:Rank()) and (not (pl == ply))) then
			ply:SendChat( COL_DARKRED .. "That player is of equal or higher rank to you!" )
			return true
		end
		util.BroadcastChat( ply:CNick() .. " healed " .. pl:CNick() .. "!" )
		pl:SetHealth( 20 )
		return true
	end
	if (cmd == "setpvp") then
		if (not ValidateFlags( ply, FLAG_SETTIME )) then return true end
		local val = args[1]
		if (not ((val == "on") or (val == "off"))) then
			ply:SendChat( "Syntax: /setpvp <on/off>" )
			return true
		end
		local b = ((val == "on") and true) or false
		core.EntityManager:EnablePVP( b )
		local str = ""
		if (b) then
			str = ply:CNick() .. " has " .. COL_DARKRED .. "enabled" .. COL_WHITE .. " PvP mode!"
		else
			str = ply:CNick() .. " has " .. COL_DARKGREEN .. "disabled" .. COL_WHITE .. " PvP mode!"
		end
		util.BroadcastChat( str )
		return true
	end
end

hooks.Add( "admin", plugin )